import tkinter as tk
import os
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
import csv
from PIL import Image, ImageTk
import logging
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

logging.basicConfig(level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')

class MovieRatingApp:
    def __init__(self, root):
        self.root = root
        root.title("Movie Rating App")
        root.geometry("900x600")

        # Get current directory
        try:
            current_dir = os.path.dirname(os.path.abspath(__file__))
        except:
            current_dir = os.getcwd()

        # Load and display movie images
        try:
            self.image1 = Image.open(os.path.join(current_dir, 'post1_relie.jpg'))
            self.image1.thumbnail((100, 300))
            self.movie1_image = ImageTk.PhotoImage(self.image1)
            self.movie1_label = tk.Label(root, image=self.movie1_image)
            self.movie1_label.grid(row=0, column=0, padx=10, pady=10)
        except Exception as e:
            print(f"Cannot load movie 1 image: {e}")
            self.movie1_label = tk.Label(root, text="Movie 1 Image Not Found")
            self.movie1_label.grid(row=0, column=0, padx=10, pady=10)

        try:
            self.image2 = Image.open(os.path.join(current_dir, "post2_family.jpg"))
            self.image2.thumbnail((100, 300))
            self.movie2_image = ImageTk.PhotoImage(self.image2)
            self.movie2_label = tk.Label(root, image=self.movie2_image)
            self.movie2_label.grid(row=0, column=1, padx=10, pady=10)
        except Exception as e:
            print(f"Cannot load movie 2 image: {e}")
            self.movie2_label = tk.Label(root, text="Movie 2 Image Not Found")
            self.movie2_label.grid(row=0, column=1, padx=10, pady=10)

        # Create rating dropdown menus
        self.movie1_rating = tk.StringVar(root, value="1")
        tk.OptionMenu(root, self.movie1_rating, "1", "2", "3", "4", "5").grid(row=1, column=0, padx=10, pady=10)

        self.movie2_rating = tk.StringVar(root, value="1")
        tk.OptionMenu(root, self.movie2_rating, "1", "2", "3", "4", "5").grid(row=1, column=1, padx=10, pady=10)

        # Create movie preference radio buttons
        self.preference = tk.IntVar()
        tk.Radiobutton(root, text="Action Movie", variable=self.preference, value=0).grid(row=2, column=0, padx=10, pady=10)
        tk.Radiobutton(root, text="Comedy Movie", variable=self.preference, value=1).grid(row=2, column=1, padx=10, pady=10)

        # Create buttons
        tk.Button(root, text="Confirm", command=self.confirm).grid(row=3, column=0, padx=10, pady=20)
        tk.Button(root, text="Clear", command=self.clear_plot).grid(row=3, column=1, padx=10, pady=20)
        tk.Button(root, text="Predict", command=self.predict_preference).grid(row=4, columnspan=2, padx=10, pady=20)
        self.predict_label = tk.Label(root, text="")
        self.predict_label.grid(row=5, columnspan=2, padx=10, pady=10)

        self.filename = os.path.join(current_dir, 'ratings.csv')

        if not os.path.isfile(self.filename):
            with open(self.filename, 'w', newline='') as file:
                writer = csv.writer(file)
                writer.writerow(["Movie1", "Movie2", "Preference"])

        # Create plot frame
        self.plot_frame = tk.Frame(root)
        self.plot_frame.grid(row=0, column=2, rowspan=4, padx=10, pady=10)
        self.plot_ratings()

    def confirm(self):
        m1_rating = self.movie1_rating.get()
        m2_rating = self.movie2_rating.get()
        preference = self.preference.get()

        with open(self.filename, 'a', newline='') as file:
            writer = csv.writer(file)
            writer.writerow([m1_rating, m2_rating, preference])

        self.plot_ratings()

    def clear_plot(self):
        with open(self.filename, 'w', newline='') as file:
            writer = csv.writer(file)
            writer.writerow(["Movie1", "Movie2", "Preference"])
        self.predict_label.config(text="")
        self.plot_ratings()
    def plot_ratings(self):
        self.plot_frame.destroy()
        self.plot_frame = tk.Frame(self.root)
        self.plot_frame.grid(row=0, column=2, rowspan=4, padx=10, pady=10)

        df = pd.read_csv(self.filename)
        action_movies = df[df['Preference'] == 0]
        comedy_movies = df[df['Preference'] == 1]

        fig, ax = plt.subplots()
        ax.grid(True)
        ax.scatter(action_movies['Movie1'], action_movies['Movie2'], color='orange', label='Action')
        ax.scatter(comedy_movies['Movie1'], comedy_movies['Movie2'], color='blue', label='Comedy')

        # Add coordinate text for each point
        for i in range(len(action_movies)):
            ax.text(action_movies['Movie1'].iloc[i], action_movies['Movie2'].iloc[i], f'({action_movies["Movie1"].iloc[i]}, {action_movies["Movie2"].iloc[i]})', fontsize=8)
        for i in range(len(comedy_movies)):
            ax.text(comedy_movies['Movie1'].iloc[i], comedy_movies['Movie2'].iloc[i], f'({comedy_movies["Movie1"].iloc[i]}, {comedy_movies["Movie2"].iloc[i]})', fontsize=8)

        ax.set_xlabel('Movie A Rating')
        ax.set_ylabel('Movie B Rating')
        ax.set_xlim([0, 6])
        ax.set_ylim([0, 6])
        ax.legend()

        canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)
        canvas.draw()
        canvas.get_tk_widget().pack()

    def predict_preference(self):
        df = pd.read_csv(self.filename)
        X = df[['Movie1', 'Movie2']].values
        y = df['Preference'].values

        # Check if there is enough data for training
        if len(X) < 1:
            self.predict_label.config(text="Not enough data for prediction, please add some ratings first")
            return

        knn = KNeighborsClassifier(n_neighbors=1)
        knn.fit(X, y)

        m1_rating = int(self.movie1_rating.get())
        m2_rating = int(self.movie2_rating.get())
        
        new_point = np.array([[m1_rating, m2_rating]])

        prediction = knn.predict(new_point)
        
        self.predict_label.config(text=f"Recommended movie type: {'Action Movie' if prediction[0] == 0 else 'Comedy Movie'}")

        self.plot_ratings()

        # Redraw plot with prediction point
        self.plot_frame.destroy()
        self.plot_frame = tk.Frame(self.root)
        self.plot_frame.grid(row=0, column=2, rowspan=4, padx=10, pady=10)

        df = pd.read_csv(self.filename)
        action_movies = df[df['Preference'] == 0]
        comedy_movies = df[df['Preference'] == 1]

        fig, ax = plt.subplots()
        ax.grid(True)
        ax.scatter(action_movies['Movie1'], action_movies['Movie2'], color='orange', label='Action')
        ax.scatter(comedy_movies['Movie1'], comedy_movies['Movie2'], color='blue', label='Comedy')
        
        # Plot new data point
        ax.scatter(new_point[:, 0], new_point[:, 1], color='red', marker='x', s=100, label='New User')
        
        # Get nearest neighbor and draw connection line
        distances, indices = knn.kneighbors(new_point)
        nearest_neighbor = X[indices[0][0]]
        ax.plot([new_point[0, 0], nearest_neighbor[0]], [new_point[0, 1], nearest_neighbor[1]], 'r--', label='Nearest Neighbor')

        # Add coordinate text
        for i in range(len(action_movies)):
            ax.text(action_movies['Movie1'].iloc[i], action_movies['Movie2'].iloc[i], f'({action_movies["Movie1"].iloc[i]}, {action_movies["Movie2"].iloc[i]})', fontsize=8)
        for i in range(len(comedy_movies)):
            ax.text(comedy_movies['Movie1'].iloc[i], comedy_movies['Movie2'].iloc[i], f'({comedy_movies["Movie1"].iloc[i]}, {comedy_movies["Movie2"].iloc[i]})', fontsize=8)
        
        # Add new point coordinate text
        ax.text(new_point[0, 0], new_point[0, 1]+0.1, f'({new_point[0, 0]}, {new_point[0, 1]})', fontsize=8)

        ax.set_xlabel('Movie A Rating')
        ax.set_ylabel('Movie B Rating')
        ax.set_xlim([0, 6])
        ax.set_ylim([0, 6])
        ax.legend()

        canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)
        canvas.draw()
        canvas.get_tk_widget().pack()

if __name__ == "__main__":
    root = tk.Tk()
    app = MovieRatingApp(root)
    root.mainloop()